Skip to main content
Version: 1.524.0

Usage

Basic Example​

import Trustchex from '@trustchex/react-native-sdk';

<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>

Props​

PropTypeRequiredDescription
baseUrlstring✅Your API base URL
sessionIdstring❌Session identifier
brandingobject❌Colors and logo
locale'en' | 'tr'❌Language
onCompleted() => void❌Called when the verification process finishes
onError(error) => void❌Error callback
onDocumentRead(result: DocumentReadResult) => void❌Called when document is read (NFC or OCR)
skipNfcResultScreenboolean❌Skip the NFC document review screen and proceed automatically after a successful NFC scan. Default: false
skipSuccessScreenboolean❌Skip the final success screen and call onCompleted immediately when the process finishes. Default: false

Document Read Event​

The onDocumentRead callback fires as soon as document data is available — immediately after a successful NFC chip read or after a successful camera OCR scan. It receives a unified DocumentReadResult object regardless of source.

import Trustchex, { type DocumentReadResult } from '@trustchex/react-native-sdk';

<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
onDocumentRead={(result: DocumentReadResult) => {
const { document } = result;

console.log(document.documentType); // "P" (passport) | "I" (ID card)
console.log(document.issuingCountry); // "DEU"
console.log(document.nationality); // "DEU"
console.log(document.documentNumber); // "C01X00T478"
console.log(document.personalNumber); // "8512310074" | null
console.log(document.lastName); // "MÜLLER"
console.log(document.firstName); // "JÜRGEN KARL"
console.log(document.sex); // "M" | "F" | "X" | "U"
console.log(document.dateOfBirth); // "1985-03-10" (ISO 8601)
console.log(document.dateOfExpiry); // "2030-11-05" (ISO 8601)
}}
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>

DocumentReadResult​

interface DocumentReadResult {
document: {
documentType: string; // "P" (passport) | "I" (ID card)
issuingCountry: string; // 3-letter ICAO country code, e.g. "TUR"
nationality: string;
documentNumber: string;
personalNumber: string | null;
lastName: string; // Best available name, e.g. "MÜLLER"
firstName: string; // Best available name, e.g. "JÜRGEN"
sex: 'M' | 'F' | 'X' | 'U';
dateOfBirth: string | null; // ISO 8601, e.g. "1990-05-15"
dateOfExpiry: string | null; // ISO 8601, e.g. "2028-03-01"
};
name: {
rawLast: string; // MRZ ASCII surname
rawFirst: string; // MRZ ASCII given name
displayLast: string; // Best Unicode form, e.g. "MÜLLER"
displayFirst: string; // Best Unicode form, e.g. "JÜRGEN"
source: 'dg11' | 'reverse_table' | 'raw';
};
face?: {
data: string; // Base64-encoded image
mimeType: string; // e.g. "image/jpeg"
};
}

Name Sources​

SourceDescription
dg11Exact printed name read from the NFC chip's DG11 file (UTF-8). Highest accuracy.
reverse_tableReconstructed via ICAO 9303 reverse transliteration (e.g. OE→Ö, UE→Ü). Applied for known countries.
rawNo conversion — display equals the raw MRZ ASCII value.

Flow Control​

Skip NFC Result Screen​

By default, after a successful NFC chip read the SDK shows a review screen where the user can verify their document data before proceeding. Set skipNfcResultScreen to bypass this screen entirely — the SDK advances automatically as soon as the NFC scan completes.

<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
skipNfcResultScreen
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>

Use onDocumentRead alongside this prop if you need to access the scanned document data without showing the review screen.

Skip Success Screen​

By default, after the verification process completes the SDK shows a success animation for 3 seconds before calling onCompleted. Set skipSuccessScreen to call onCompleted immediately with no animation or delay.

<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
skipSuccessScreen
onCompleted={() => {
// Called immediately when verification is complete
navigation.navigate('Home');
}}
onError={(error) => console.error(error)}
/>

Both props can be combined:

<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
skipNfcResultScreen
skipSuccessScreen
onDocumentRead={(result) => console.log(result.name.displayFirst)}
onCompleted={() => navigation.navigate('Home')}
onError={(error) => console.error(error)}
/>

Accepted Document Types​

Which documents a user may scan is set per workflow, not in the app. In the dashboard, open Workflows, edit the Identity Document Scan (or Identity Document eID Scan) step, and choose Allowed Document Types:

SettingWhat the user can scan
None selected (default)ID card or passport
Identity CardID cards only
PassportPassports only

No SDK prop or code change is needed. The SDK reads the setting from the verification session and adapts the scan screen:

  • Guide and instructions. The scan frame shows a drawing of the document to hold up, and the instruction names it ("Show the front of the card", "Show the photo page"). When both types are allowed, the guide alternates between an ID card and a passport until the document is recognised.
  • Other documents are rejected on the spot. A document that isn't allowed is never captured. The user is asked for the right one instead ("Show your ID card" or "Show your passport"), and scanning continues as soon as an allowed document is shown.
  • ID cards: front first. For ID cards, the front is always read before the back. Showing the back first prompts the user to turn the card over.

Allowed Countries, on the same step, limits documents by issuing country. That check runs once the document has been read: a document from another country is rejected, and the user is asked to scan again.

With these checks, a user can't complete the step with a document the workflow doesn't accept.

With Branding​

<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123"
branding={{
logoUrl: 'https://your-logo.png',
primaryColor: '#1E40AF',
secondaryColor: '#F8FAFC',
tertiaryColor: '#DC2626'
}}
locale="en"
onCompleted={() => console.log('Done')}
/>

Deep link functionality is an optional feature if you want to publish a standalone app. To process deep links with the SDK, you need to configure deep links in your app and set up the required hooks to handle incoming URLs.

iOS - Add to Info.plist:

<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLSchemes</key>
<array>
<string>yourapp</string>
</array>
</dict>
</array>

Android - Add to AndroidManifest.xml. Keep android:launchMode="singleTask" so a deep link that arrives while the app is already open is delivered to the existing activity instead of starting a new one:

<activity android:name=".MainActivity" android:launchMode="singleTask">
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="yourapp" />
</intent-filter>
</activity>

Import and use the handleDeepLink function to process incoming URLs:

import React from 'react';
import { AppState, Linking } from 'react-native';
import Trustchex, { handleDeepLink } from '@trustchex/react-native-sdk';

const App = () => {
const appState = React.useRef(AppState.currentState);
const [baseUrl, setBaseUrl] = React.useState<string | undefined>();
const [sessionId, setSessionId] = React.useState<string>('');
const lastHandledUrl = React.useRef<string | null>(null);

const processDeepLink = React.useCallback((url: string | null) => {
// Ignore empty URLs and re-processing the same URL (getInitialURL returns
// the last intent on every foreground, so this would otherwise re-fire).
if (!url || url === lastHandledUrl.current) return;
const [bUrl, sId] = handleDeepLink({ url });
if (bUrl && sId) {
lastHandledUrl.current = url;
setBaseUrl(bUrl);
setSessionId(sId);
}
}, []);

React.useEffect(() => {
// Cold start (app launched by the link).
Linking.getInitialURL().then(processDeepLink);

// Warm start (link arrives while the app is running).
const urlSub = Linking.addEventListener('url', ({ url }) =>
processDeepLink(url)
);

// On Android's New Architecture (bridgeless) the warm-start 'url' event can
// be dropped ("Tried to access onNewIntent while context is not ready"), so
// re-read the launch intent whenever the app returns to the foreground to
// recover it. Requires the MainActivity.onNewIntent override below.
const appStateSub = AppState.addEventListener('change', (next) => {
if (appState.current.match(/inactive|background/) && next === 'active') {
Linking.getInitialURL().then(processDeepLink);
}
appState.current = next;
});

return () => {
urlSub.remove();
appStateSub.remove();
};
}, [processDeepLink]);

return (
<Trustchex
baseUrl={baseUrl}
sessionId={sessionId}
onCompleted={() => console.log('Done')}
onError={(error) => console.error(error)}
/>
);
};

A link that arrives while the app is already open needs a small native override on each platform. Without these, the link is silently dropped and the user stays on the first screen even though the JavaScript above is correct.

Android — override onNewIntent in your MainActivity to store the fresh intent, so Linking.getInitialURL() (used by the foreground re-check above) returns the new link rather than the original launch URL:

// MainActivity.kt
import android.content.Intent

override fun onNewIntent(intent: Intent) {
setIntent(intent)
super.onNewIntent(intent)
}

iOS — forward incoming URLs to RCTLinkingManager in your AppDelegate. This is what emits the JavaScript 'url' event while the app is running:

// AppDelegate.swift
import React // exposes RCTLinkingManager

func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
return RCTLinkingManager.application(app, open: url, options: options)
}

// Universal Links (https://…):
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void
) -> Bool {
return RCTLinkingManager.application(
application, continue: userActivity, restorationHandler: restorationHandler)
}

The handleDeepLink function parses URLs with the format:

scheme://app-url/your-api.com/verification-session/session-123

And returns [baseUrl, sessionId] that you can use with the Trustchex component.

Sessions​

Create sessions using the REST API.

Session Access Methods​

The SDK provides multiple ways for users to access their verification session:

Users click a link that opens the app directly with the session:

// Deep link format: yourapp://app-url/your-api.com/verification-session/session-123
<Trustchex
baseUrl="https://your-api.com"
sessionId="session-123" // From deep link
onCompleted={() => console.log('Done')}
/>

Benefits:

  • Seamless user experience - one tap to start
  • Direct navigation to verification
  • No manual input required
  • Works great for email and SMS campaigns

Users scan a QR code that contains the session information. The SDK includes a built-in QR scanner accessible from the welcome screen.

Benefits:

  • Quick and contactless
  • No typing required
  • Ideal for in-person verification
  • Built-in scanner included in SDK

3. Session Code Entry (Alternative)​

Users can manually enter an 8-character alphanumeric code:

<Trustchex
baseUrl="https://your-api.com"
// No sessionId prop needed - user enters code manually
onCompleted={() => console.log('Done')}
/>

When no sessionId is provided, the SDK displays a screen where users can:

  • Enter the 8-character session code
  • Scan a QR code

Use Cases:

  • Fallback when QR/deep link unavailable
  • Phone/voice support scenarios
  • Print media without QR capability

Creating Sessions​

When creating a session via the REST API, you'll receive access methods in the response:

const response = await fetch('https://your-api.com/api/v1/verification-sessions', {
method: 'POST',
headers: { 'x-api-key': 'YOUR_API_KEY' },
body: JSON.stringify({
workflowId: 'workflow-123',
email: 'user@example.com'
})
});

const { deepLink, qrCodeLink, sessionCode } = await response.json();

// Use deepLink for direct app navigation (recommended)
// Use qrCodeLink to generate QR code (recommended)
// Use sessionCode as alternative access method